#!/bin/sh
#-
# Copyright (c) 2013 iXsystems, Inc., All rights reserved.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL Jordan Hubbard OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

. /etc/rc.subr

#
#	LDAP settings
#
: ${LDAP_CONFIG_PATH:="/etc/directoryservice/LDAP"}
: ${LDAP_CONFIG_FILE:="${LDAP_CONFIG_PATH}/config"}
: ${NSS_LDAP_CONF:="/usr/local/etc/nss_ldap.conf"}
: ${NSS_LDAP_SECRET:="/usr/local/etc/nss_ldap.secret"}
: ${LDAP_CONF:="/usr/local/etc/openldap/ldap.conf"}
: ${CERT_FILE:="/usr/local/etc/certs/cacert.crt"}
: ${LDAP_TIMEOUT:="0"}
: ${LDAP_TOOL:="/usr/local/bin/ldaptool"}

__LDAP_tc()
{
	local timeout=$1
	shift
	local args="$*"

	local i=0
	local ret=1
	local lf="$(mktemp /tmp/tmp.XXXXXX)"

	lockf -k -s -t 0 ${lf} ${args} &
	ret=$?
	lpid=$!

	if [ "${ret}" != "0" ]
	then
		return ${ret}
	fi

	ret=2
	while [ ${i} -lt ${timeout} ]
	do
		sleep 1

		if lockf -k -s -t 0 ${lf} /usr/bin/true
		then
			rm -f ${lf}
			ret=0
			break
		fi

		: $((i += 1))
	done

	kill $! >/dev/null 2>&1
	pid="$(ps -axwww|grep "$args"|grep -v grep|awk '{ print $1 }')"
	if [ -n "${pid}" ]
	then
		kill ${pid} >/dev/null 2>&1
	fi

	pid="$(ps -axwww|grep "$args"|grep -v grep|awk '{ print $1 }')"
	if [ -n "${pid}" ]
	then
		kill -9 ${pid} >/dev/null 2>&1
	fi

	wait ${lpid}
	ret=$?

	rm -f ${lf}
	return ${ret}
}

LDAP_get_user_by_DN()
{
	local dn="${1}"
	local host="$(LDAP_get ldap_host)"
	local port="$(LDAP_get ldap_port)"
	local basedn="$(LDAP_get ldap_basedn)"
	local binddn="$(LDAP_get ldap_binddn)"
	local bindpw="$(LDAP_get ldap_bindpw)"
	local tmpfile="$(mktemp -q /var/tmp/.adbarXXXXXX)"

	cat<<-__EOF__>"${tmpfile}"
	/usr/local/bin/ldapsearch \
	    -H 'ldap://${host}:${port}' \
	    -b '${dn}' \
	    -D '${binddn}' \
	    -w '${bindpw}' \
	    -s sub \
	    -x \
	    -z 0 \
	    -LLL \
	    -l '${LDAP_TIMEOUT}' 
__EOF__

	eval $(cat "${tmpfile}")
	rm "${tmpfile}"
}

LDAP_get_binddn_uid()
{
	LDAP_get_user_by_DN "$(LDAP_get ldap_binddn)" | \
		egrep -iw '^uid' | awk '{ print $2 }'
}

__do_LDAP_get()
{
	local prefix="${1}"
	local name="${2}"
	local var=\$$(printf "${prefix}${name}")
	local val=$(eval "echo ${var} 2>/dev/null")

	__unescape "${val}"
}

LDAP_get()
{
	local vars="${*}"
	local prefix="__ldap_"

	for v in ${vars}
	do
		local var=\$$(printf "${v}")
		local val=$(eval "echo ${var} 2>/dev/null")

		if [ -n "${val}" ]
		then
			echo "${val}"
		else
			__do_LDAP_get "${prefix}" "${v}" 2>/dev/null
		fi
	done
}

__do_LDAP_set()
{
	local prefix="${1}"
	local var="${2}"
	local val=$(__escape "${3}")
	local pair="${var}=${val}"

	eval "${prefix}${pair}"
}

LDAP_set()
{
	local var="${1}"
	local val="${2}"
	local prefix="__ldap_"

	__do_LDAP_set "${prefix}" "${var}" "${val}" 2>/dev/null
}

LDAP_show_config()
{
	printf "LDAP Config:\n"
	printf "+---------------------------------------------------------+\n"
	printf "ldap_hostname:           %s\n" $(LDAP_get ldap_hostname)
	printf "ldap_basedn:             %s\n" $(LDAP_get ldap_basedn)
	printf "ldap_anonbind:           %s\n" $(LDAP_get ldap_anonbind)
	printf "ldap_binddn:             %s\n" $(LDAP_get ldap_binddn)
	printf "ldap_bindpw:             %s\n" $(LDAP_get ldap_bindpw)
	printf "ldap_pwencryption:       %s\n" $(LDAP_get ldap_pwencryption)
	printf "ldap_usersuffix:         %s\n" $(LDAP_get ldap_usersuffix)
	printf "ldap_groupsuffix:        %s\n" $(LDAP_get ldap_groupsuffix)
	printf "ldap_passwordsuffix:     %s\n" $(LDAP_get ldap_passwordsuffix)
	printf "ldap_machinesuffix:      %s\n" $(LDAP_get ldap_machinesuffix)
	printf "ldap_sudosuffix:         %s\n" $(LDAP_get ldap_sudosuffix)
	printf "ldap_kerberos_realm_id:  %s\n" $(LDAP_get ldap_kerberos_realm_id)
	printf "ldap_kerberos_keytab_id: %s\n" $(LDAP_get ldap_kerberos_keytab_id)
	printf "ldap_ssl:                %s\n" $(LDAP_get ldap_ssl)
	printf "ldap_certificate_id:     %s\n" $(LDAP_get ldap_certificate_id)
	printf "ldap_idmap_backend:      %s\n" $(LDAP_get ldap_idmap_backend)
	printf "ldap_has_samba_schema:   %s\n" $(LDAP_get ldap_has_samba_schema)
	printf "ldap_enable:             %s\n" $(LDAP_get ldap_has_samba_schema)
	printf "+---------------------------------------------------------+\n"
}

LDAP_has_samba_schema()
{
	local has_samba_schema="$(LDAP_get ldap_has_samba_schema)"
	if [ "${has_samba_schema}" = "1" ]
	then
		return 0
	fi
	return 1
}

LDAP_log()
{
	local args="$*"

	local on="$(LDAP_get ldap_verbose_logging)"
	if [ "${on}" = "1" ]
	then
		logger -t "LDAP" ${args} >/dev/null 2>&1
	fi
}

LDAP_load_values()
{
	if ! LDAP_generate_config
	then
		return 1
	fi

	exec 3<&0
	exec 0<"${LDAP_CONFIG_FILE}"

	while read -r line
	do
		local var="$(echo ${line}|cut -f1 -d=|sed -Ee 's#^[[:space:]]+##' -e 's#[[:space:]]+$##')"
		local val="$(echo ${line}|cut -f2- -d=|sed -Ee 's#^[[:space:]]+##' -e 's#[[:space:]]+$##')"

		LDAP_set "${var}" "${val}"
	done
	exec 0<&3

	return 0
}

LDAP_generate_config()
{
	local res=0

	${LDAP_TOOL} get config_file > "${LDAP_CONFIG_FILE}"
	res=$?
	/bin/chmod 600 "${LDAP_CONFIG_FILE}"

	return ${res}
}

LDAP_load_bindpw()
{
	local tmpfile="$(mktemp -q /var/tmp/.adfooXXXXXX)"

	cat << __SQL__ | ${FREENAS_SQLITE_CMD} -line ${FREENAS_CONFIG} > ${tmpfile}
	SELECT
		ldap_bindpw

	FROM
		directoryservice_ldap

	ORDER BY
		-id

	LIMIT 1;
__SQL__

	exec 3<&0
	exec 0<"${tmpfile}"
	while read -r line
	do
		local var="$(echo ${line}|cut -f1 -d=|sed -Ee 's#^[[:space:]]+##' -e 's#[[:space:]]+$##')"
		local val="$(echo ${line}|cut -f2- -d=|sed -Ee 's#^[[:space:]]+##' -e 's#[[:space:]]+$##')"

		LDAP_set "${var}" "$(/usr/local/bin/midclt call notifier.pwenc_decrypt ${val})"
	done
	exec 0<&3
	rm "${tmpfile}"
}

LDAP_init()
{
	if ! LDAP_load_values
	then
		return 1
	fi

	LDAP_load_bindpw
	return 0
}

ldap_enabled()
{
	enabled="$(${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "\
	SELECT
		ldap_enable
	FROM
		directoryservice_ldap
	ORDER BY
		-id
	LIMIT 1")"

	if [ "${enabled}" = "1" ]
	then
		return 0
	elif [ "${enabled}"  = "0" ]
	then
		return 1
	fi

	return 2
}

ldap_set()
{
	local enable="${1}"

	if [ -z "${enable}" ]
	then
		return 0
	fi

	${FREENAS_SQLITE_CMD} ${FREENAS_CONFIG} "\
	UPDATE
		directoryservice_ldap
	SET
		ldap_enable = ${enable}
	"

	return $?
}
